home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / SDKs / Apple Game Sprockets / InputSprocket / Sample Drivers / ISp Sample ADB Sources / ISpSampleADB.cp < prev    next >
Encoding:
Text File  |  1998-07-15  |  56.6 KB  |  1,802 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************
  2.  
  3. File:      ISpSampleADB.cp
  4.  
  5. Copyright © 1996, 1997, 1998 Apple Computer, Inc., All Rights Reserved
  6.  
  7.  
  8. You may incorporate this sample code into your applications without
  9. restriction, though the sample code has been provided "AS IS" and the
  10. responsibility for its operation is 100% yours.  However, what you are
  11. not permitted to do is to redistribute the source as "DSC Sample Code"
  12. after having made changes. If you're going to re-distribute the source,
  13. we require that you make it clear in the source that the code was
  14. descended from Apple Sample Code, but that you've made changes.
  15.  
  16. *************************************************************************************/
  17.  
  18. #ifndef __INPUTSPROCKET__
  19. #include <InputSprocket.h>
  20. #endif
  21.  
  22. #include "InputSprocketDriver.h"
  23. #include "InputSprocketDefer.h"
  24. #include "ISpSampleADB.h"
  25. #include "ISpSampleADBMain.h"
  26.  
  27. #ifndef __RESOURCES__
  28. #include <Resources.h>
  29. #endif
  30.  
  31. #ifndef __TEXTUTILS__
  32. #include <TextUtils.h>
  33. #endif
  34.  
  35. #ifndef __QDOFFSCREEN__
  36. #include <QDOffscreen.h>
  37. #endif
  38.  
  39. #ifndef __DESKBUS__
  40. #include <DeskBus.h>
  41. #endif
  42.  
  43. #include "ISpPlugInUI.h"
  44. #include "dprintf.h"
  45.  
  46. #include "ADBUtils.h"
  47. #include "Common.h"
  48. #include "DialogUtils.h"
  49.  
  50. /* =============================================================================
  51.  *        ADBINIT ROUTINE
  52.  * ========================================================================== */
  53. extern "C" pascal void ADBInitProc(
  54.     char            inPostprocess);
  55.  
  56. extern "C" void PatchADBServiceRoutine(
  57.     UInt8                    inCommand,
  58.     void                     *inBuffer,
  59.     UInt32                    inDataArea);
  60.  
  61. SidewinderPro *        SidewinderPro::gSidewinders[16] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  62.  
  63. // string replace stuff
  64. static    StringHandle    HandleToStringHandle(Handle handle);
  65. static    Handle            StringHandleToHandle(StringHandle stringHandle);
  66.  
  67. SidewinderPro::SidewinderPro(ADBAddress inADBAddr, const FSSpec &inFileSpec)
  68. {
  69.     OSStatus err;
  70.     
  71.     // assign our arguments
  72.     mADBAddress = inADBAddr;
  73.     mFileSpec = inFileSpec;
  74.     
  75.     // clear the device
  76.     mDevice = nil;
  77.  
  78.     // intialize ui variables
  79.     mDialog                 = nil;
  80.     mBaseDITLCount            = nil;
  81.     mResRef                 = nil;
  82.     mVisable                 = false;
  83.     mVirtualElementsValid     = false;    // Init has not been called yet
  84.     mActive                 = false;
  85.     mPatched                = false;
  86.     mOrphan                 = false;
  87.     mADBDefer                = 0;
  88.     
  89.     mReverseStickVertical = false;
  90.     mReverseHatVertical = false;
  91.     mReverseRudder = false;
  92.     mReverseThrottle = false;
  93.         
  94.     // initialize old state
  95.     mOldState.xAxis = kISpAxisMiddle;
  96.     mOldState.yAxis = kISpAxisMiddle;
  97.     mOldState.throttle = kISpAxisMinimum;
  98.     mOldState.rudder = kISpAxisMiddle;
  99.     mOldState.hat = kISpPadIdle;
  100.     
  101.     {
  102.         for(UInt32 itr = 0; itr < kNumSidewinderButtons; itr++)
  103.             { mOldState.buttons[itr] = 0; }
  104.     }
  105.     
  106.     // zero high level data
  107.     StateToHighLevelData (mOldState, mOldHLData);
  108.     SetAsFields (mOldHLData);
  109.     
  110.     // zero dialog item to need mapping
  111.     {
  112.         for(UInt32 itr = 0; itr <= kDialogItem_NumPopups; itr++)
  113.             { mDialogItemToNeedMapping[itr] = kUnsetIndex; }
  114.     }
  115.     
  116.     ClearVirtuals();
  117.         
  118.     err = CreateDevice();
  119.     WARNING(err == noErr, "CreateDevice failed in SidewinderPro::SidewinderPro");
  120.  
  121.     err = Patch();
  122.     WARNING(err == noErr, "Patch failed in SidewinderPro::SidewinderPro");
  123.  
  124.     mActive = true;
  125. }
  126.  
  127. SidewinderPro::~SidewinderPro()
  128. {
  129.     OSStatus err = noErr;
  130.     
  131.     if (mPatched) { Unpatch(); }
  132.     DisposeDevice();
  133. }
  134.  
  135. OSStatus SidewinderPro::CreateDevice(void)
  136. {
  137.     OSStatus err;
  138.     
  139.     // ================== step 1 create the device ==================
  140.     err = CreateDeviceFromResource(kDeviceResource_SidewinderPro, (UInt32) this, mDevice);    
  141.     WARNING(err == noErr, "SidewinderPro CreateDeviceFromResource failed");
  142.  
  143.     // ================== step 2 create the axis elements ==================
  144.     err = CreateElementFromResource(kElementResource_XAxis, kElementConfigResource_SymetricAxis, mDevice, mXAxis);
  145.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on XAxis");    
  146.  
  147.     err = CreateElementFromResource(kElementResource_YAxis, kElementConfigResource_SymetricAxis, mDevice, mYAxis);
  148.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on YAxis");    
  149.  
  150.     err = CreateElementFromResource(kElementResource_Throttle, kElementConfigResource_AsymetricAxis, mDevice, mThrottle);
  151.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on Throttle");    
  152.  
  153.     err = CreateElementFromResource(kElementResource_Rudder, kElementConfigResource_SymetricAxis, mDevice, mRudder);
  154.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on Rudder");    
  155.  
  156.     // ================== step 2 create the hat elements ==================
  157.     err = CreateElementFromResource(kElementResource_Hat, kElementConfigResource_DPad1, mDevice, mHat);
  158.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on hat");    
  159.  
  160.     // ================== step 3 create the button elements ==================
  161.     err = CreateElementFromResource(kElementResource_Trigger, kElementConfigResource_Button1, mDevice, mButtons[0]);
  162.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on trigger");    
  163.  
  164.     err = CreateElementFromResource(kElementResource_TopButton, kElementConfigResource_BlankButton, mDevice, mButtons[1]);
  165.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on top button");    
  166.  
  167.     err = CreateElementFromResource(kElementResource_StickHighButton, kElementConfigResource_BlankButton, mDevice, mButtons[2]);
  168.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on stick high button");    
  169.  
  170.     err = CreateElementFromResource(kElementResource_StickLowButton, kElementConfigResource_BlankButton, mDevice, mButtons[3]);
  171.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on stick low button");    
  172.     
  173.     err = CreateElementFromResource(kElementResource_BaseFarLeft, kElementConfigResource_BlankButton, mDevice, mButtons[4]);
  174.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on base far left button");    
  175.  
  176.     err = CreateElementFromResource(kElementResource_BaseFarRight, kElementConfigResource_BlankButton, mDevice, mButtons[5]);
  177.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on base far right button");    
  178.  
  179.     err = CreateElementFromResource(kElementResource_BaseNearLeft, kElementConfigResource_BlankButton, mDevice, mButtons[6]);
  180.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on base near left button");    
  181.  
  182.     err = CreateElementFromResource(kElementResource_BaseNearRight, kElementConfigResource_BlankButton, mDevice, mButtons[7]);
  183.     WARNING(err == noErr, "SidewinderPro CreateElementFromResource failed on base near right button");    
  184.     
  185.     // ================== step 4 push inital values for axis elements  ==================
  186.     AbsoluteTime time = ISpUptime();
  187.     err = ISpElement_PushSimpleData(mXAxis, mOldState.xAxis, &time);
  188.     WARNING(err == noErr, "ISpElement_PushSimpleData failed in CreateDevice");
  189.  
  190.     err = ISpElement_PushSimpleData(mYAxis, mOldState.yAxis, &time);
  191.     WARNING(err == noErr, "ISpElement_PushSimpleData failed in CreateDevice");
  192.  
  193.     err = ISpElement_PushSimpleData(mThrottle, mOldState.throttle, &time);
  194.     WARNING(err == noErr, "ISpElement_PushSimpleData failed in CreateDevice");
  195.  
  196.     err = ISpElement_PushSimpleData(mRudder, mOldState.rudder, &time);
  197.     WARNING(err == noErr, "ISpElement_PushSimpleData failed in CreateDevice");
  198.  
  199.     return err;        
  200. }
  201.  
  202. OSStatus SidewinderPro::DisposeDevice(void)
  203. {
  204.     OSStatus err;
  205.     
  206.     err = ISpElement_Dispose(mXAxis);
  207.     WARNING(err == noErr, "SidewinderPro ISpElement_Dispose failed on XAxis");
  208.  
  209.     err = ISpElement_Dispose(mYAxis);
  210.     WARNING(err == noErr, "SidewinderPro ISpElement_Dispose failed on YAxis");
  211.  
  212.     err = ISpElement_Dispose(mThrottle);
  213.     WARNING(err == noErr, "SidewinderPro ISpElement_Dispose failed on Throttle");
  214.  
  215.     err = ISpElement_Dispose(mRudder);
  216.     WARNING(err == noErr, "SidewinderPro ISpElement_Dispose failed on Rudder");
  217.  
  218.     err = ISpElement_Dispose(mHat);
  219.     WARNING(err == noErr, "SidewinderPro ISpElement_Dispose failed on Hat");
  220.      
  221.     int itr;
  222.     for(itr = 0; itr < kNumSidewinderButtons; itr++)
  223.     {
  224.         err = ISpElement_Dispose(mButtons[itr]);
  225.         WARNING(err == noErr, "SidewinderPro ISpElement_Dispose failed on a generic button");
  226.     }
  227.     
  228.     err = ISpDevice_Dispose(mDevice);
  229.     WARNING(err == noErr, "SidewinderPro ISpDevice_Dispose failed");
  230.     
  231.     return err;
  232. }
  233.  
  234. /* =============================================================================
  235.  *        Patch (private)
  236.  *
  237.  *    Installs the appropriate patch for this mouse.
  238.  * ========================================================================== */
  239. OSStatus SidewinderPro::Patch(void)
  240. {
  241.     WARNING(mPatched == false, "SidewinderPro patch called but we are already patched!");
  242.  
  243.     OSStatus            err;    
  244.  
  245.     if (!mOrphan)
  246.     {
  247.         WARNING((mADBAddress >= 0) && (mADBAddress <= 15),    "SidewinderPro Patch bad address");
  248.  
  249.         err = ISpAllocateADBDeferBlock(&mADBDefer);
  250.         if (noErr != err)
  251.             return err;            // could not allocate
  252.  
  253.         err = ISpInstallADBDefer(mADBDefer,mADBAddress,(ISpADBDeferCallbackProcPtr) PatchADBServiceRoutine,
  254.                                  (UInt32) this,nil,nil);
  255.  
  256.         WARNING(err == noErr, "SidewinderPro patch failed to aquire defer block (will not patch)");
  257.         if (noErr != err)
  258.             return err;            // could not install
  259.     }
  260.  
  261.     // mark as patched
  262.     mPatched = true;
  263.  
  264.     return noErr;
  265. }
  266.  
  267.  
  268. /* =============================================================================
  269.  *        Unpatch (private)
  270.  *
  271.  *    Removes the patch that we installed for this mouse.
  272.  * ========================================================================== */
  273. OSStatus SidewinderPro::Unpatch(void)
  274. {
  275.     WARNING(mPatched == true, "SidewinderPro Unpatch called but were are not patched!");
  276.     
  277.     if (!mOrphan)
  278.     {
  279.         OSErr            err;
  280.  
  281.         WARNING((mADBAddress >= 0) && (mADBAddress <= 15),    "SidewinderPro Unpatch bad address");
  282.         
  283.         err = ISpRemoveADBDefer(mADBDefer);
  284.         if (noErr != err)
  285.             return err;
  286.  
  287.     // Ignore memory release errors
  288.         (void) ISpDisposeADBDeferBlock(mADBDefer);
  289.     }
  290.     
  291.     // mark as unpatched
  292.     mPatched = false;        
  293.     
  294.     return noErr;
  295. }
  296.  
  297. /* =============================================================================
  298.  *        PatchADBServiceRoutine (local, c)
  299.  *
  300.  * ========================================================================== */
  301. void PatchADBServiceRoutine(
  302.     UInt8                    inCommand,
  303.     void                    *inBuffer,
  304.     UInt32                    inDataArea)
  305. {
  306.     SidewinderPro* sidewinderProCore = (SidewinderPro*) inDataArea;
  307.     WARNING(sidewinderProCore != nil, "Sidewinder: patch object pointer was null");
  308.  
  309.     if (sidewinderProCore != nil)
  310.         { sidewinderProCore->ParseData(inBuffer, inCommand); }
  311. }
  312.  
  313.  
  314. OSStatus SidewinderPro::Init(UInt32 count, ISpNeed needs[], ISpElementReference virtualElements[], 
  315.                 Boolean used[], OSType appCreatorCode, OSType subCreatorCode, 
  316.                 UInt32 reserved, void* reserved2)
  317. {
  318.     // dont use these four
  319.     appCreatorCode;
  320.     subCreatorCode;
  321.     reserved;
  322.     reserved2;
  323.     
  324.     UInt32 itr;
  325.  
  326.     // allocate arrays to hold references and needs and copy the data in
  327.     mReferences = (ISpElementReference *) NewPtrSysClear(count * sizeof(ISpElementReference));
  328.     WARNING(mReferences != nil,    "SidewinderPro::Init failed to allocate mReferences");
  329.     if (mReferences == nil) { return -1; }
  330.  
  331.     mNeeds = (ISpNeed *) NewPtrSysClear(count * sizeof(ISpNeed));
  332.     WARNING(mNeeds != nil,        "SidewinderPro::Init failed to allocate mNeeds");
  333.     if (mNeeds == nil)
  334.     {
  335.         DisposePtr((Ptr) mReferences);
  336.         mReferences = nil;
  337.         return - 1;
  338.     }
  339.  
  340.     mNumNeeds = count;
  341.  
  342.     // copy the data
  343.     for(itr = 0; itr < count; itr++)
  344.     {
  345.         mReferences[itr] = virtualElements[itr];
  346.         mNeeds[itr] = needs[itr];
  347.     }
  348.     
  349.     AutoConfigure(used);    // sets mDialogItemToNeedMapping and the virtual elements
  350.  
  351.     mVirtualElementsValid = true;
  352.     mDirty = false;     
  353.  
  354.     // set initial values
  355.     SetAsFields (mOldHLData);
  356.     PushDataToVirtuals (mOldHLData);
  357.         
  358.     return noErr;
  359. }
  360.  
  361. void SidewinderPro::AutoConfigure(Boolean used[])
  362. {
  363.     // mVirtualElement might not be valid yet
  364.     WARNING(mNeeds != nil,                        "SidewinderPro::AutoConfigure mNeeds was nil");
  365.     WARNING(used != nil,                        "SidewinderPro::AutoConfigure used was nil");
  366.     WARNING(mDialogItemToNeedMapping != nil,    "SidewinderPro::AutoConfigure mDialogItemToNeepMapping was nil");
  367.     
  368.     // AUTOCONFIGURE
  369.     UInt32 buttonCount = 0;                        // number of buttons we have auto configured
  370.     UInt32 itr;                                    // used for general iterating
  371.     
  372.     // clear out all the entries
  373.     for(itr = 0; itr <= kDialogItem_NumPopups; itr++)
  374.         { mDialogItemToNeedMapping[itr] = kUnsetIndex; }
  375.  
  376.     // first pass find movement or dpad movement needs and map them to the stick
  377.     for(itr = 0; itr < mNumNeeds; itr++)
  378.     {
  379.         if (mNeeds[itr].flags & kISpNeedFlag_Utility) continue;    // we don't autoconfig to utility needs
  380.         
  381.         if (used[itr] && (mNeeds[itr].flags & kISpNeedFlag_NoMultiConfig)) { continue; }
  382.         
  383.         Boolean movement_need        = mNeeds[itr].theKind == kISpElementKind_Movement;
  384.         Boolean dpad_movement_need    = (mNeeds[itr].theKind == kISpElementKind_DPad) && 
  385.                                       ((mNeeds[itr].theLabel == kISpElementLabel_Pad_Move) || 
  386.                                        (mNeeds[itr].theLabel == kISpElementLabel_Pad_Move_Horiz));
  387.         
  388.         if (movement_need || dpad_movement_need)
  389.         {
  390.             WARNING(mDialogItemToNeedMapping[kDialogItem_StickUp] == kUnsetIndex,    "Sidewinder:Movement already assigned!");
  391.             
  392.             mDialogItemToNeedMapping[kDialogItem_StickUp]        = itr;
  393.             mDialogItemToNeedMapping[kDialogItem_StickLeft]        = itr;
  394.             mDialogItemToNeedMapping[kDialogItem_StickDown]        = itr;
  395.             mDialogItemToNeedMapping[kDialogItem_StickRight]    = itr;
  396.             
  397.             used[itr] = true;
  398.             
  399.             break;
  400.         }
  401.     }
  402.     
  403.     // second pass pov hats
  404.     for(itr = 0; itr < mNumNeeds; itr++)
  405.     {
  406.         if (mNeeds[itr].flags & kISpNeedFlag_Utility) continue;    // we don't autoconfig to utility needs
  407.         
  408.         if (used[itr] && (mNeeds[itr].flags & kISpNeedFlag_NoMultiConfig)) { continue; }
  409.         
  410.         // pov hat need
  411.         if ((mNeeds[itr].theKind == kISpElementKind_DPad) && 
  412.             ((mNeeds[itr].theLabel == kISpElementLabel_Pad_POV) || 
  413.              (mNeeds[itr].theLabel == kISpElementLabel_Pad_POV_Horiz)))
  414.         {
  415.             WARNING(mDialogItemToNeedMapping[kDialogItem_StickUp] == kUnsetIndex,    "Sidewinder:Movement already assigned!");
  416.             
  417.             mDialogItemToNeedMapping[kDialogItem_StickUp]        = itr;
  418.             mDialogItemToNeedMapping[kDialogItem_StickLeft]        = itr;
  419.             mDialogItemToNeedMapping[kDialogItem_StickDown]        = itr;
  420.             mDialogItemToNeedMapping[kDialogItem_StickRight]    = itr;
  421.             
  422.             used[itr] = true;
  423.             
  424.             break;
  425.         }
  426.     }
  427.     
  428.     // third pass axis needs
  429.     for(itr = 0; itr < mNumNeeds; itr++)
  430.     {
  431.         if (mNeeds[itr].flags & kISpNeedFlag_Utility) continue;    // we don't autoconfig to utility needs
  432.  
  433.         if (used[itr] && (mNeeds[itr].flags & kISpNeedFlag_NoMultiConfig)) { continue; }
  434.  
  435.         if (mNeeds[itr].theKind != kISpElementKind_Axis) { continue; }
  436.  
  437.         switch(mNeeds[itr].theLabel)
  438.         {
  439.             case kISpElementLabel_Axis_XAxis:
  440.             case kISpElementLabel_Axis_Roll:
  441.                 if ((mDialogItemToNeedMapping[kDialogItem_StickLeft] == kUnsetIndex) &&
  442.                     (mDialogItemToNeedMapping[kDialogItem_StickRight] == kUnsetIndex))
  443.                 {
  444.                     mDialogItemToNeedMapping[kDialogItem_StickLeft] = itr;
  445.                     mDialogItemToNeedMapping[kDialogItem_StickRight] = itr;
  446.  
  447.                     used[itr] = true;
  448.                 }
  449.                 break;
  450.             case kISpElementLabel_Axis_YAxis:
  451.             case kISpElementLabel_Axis_Pitch:
  452.                 if ((mDialogItemToNeedMapping[kDialogItem_StickUp] == kUnsetIndex) &&
  453.                     (mDialogItemToNeedMapping[kDialogItem_StickDown] == kUnsetIndex))
  454.                 {
  455.                     mDialogItemToNeedMapping[kDialogItem_StickUp] = itr;
  456.                     mDialogItemToNeedMapping[kDialogItem_StickDown] = itr;
  457.                 
  458.                     used[itr] = true;
  459.                 }
  460.                 break;
  461.  
  462.             case kISpElementLabel_Axis_Rudder:
  463.             case kISpElementLabel_Axis_Yaw:
  464.                 if ((mDialogItemToNeedMapping[kDialogItem_RudderLeft] == kUnsetIndex) &&
  465.                     (mDialogItemToNeedMapping[kDialogItem_RudderRight] == kUnsetIndex))
  466.                 {
  467.                     mDialogItemToNeedMapping[kDialogItem_RudderLeft] = itr;
  468.                     mDialogItemToNeedMapping[kDialogItem_RudderRight] = itr;
  469.                     
  470.                     used[itr] = true;
  471.                 }
  472.             break;    
  473.  
  474.             case kISpElementLabel_Axis_Throttle:
  475.                 if ((mDialogItemToNeedMapping[kDialogItem_ThrottleLower] == kUnsetIndex) &&
  476.                     (mDialogItemToNeedMapping[kDialogItem_ThrottleHigher] == kUnsetIndex))
  477.                 {
  478.                     mDialogItemToNeedMapping[kDialogItem_ThrottleLower] = itr;
  479.                     mDialogItemToNeedMapping[kDialogItem_ThrottleHigher] = itr;
  480.                     
  481.                     used[itr] = true;
  482.                 }
  483.             break;
  484.     
  485.         }
  486.     }
  487.     
  488.     // fourth and final pass button mNeeds
  489.     for(itr = 0; itr < mNumNeeds; itr++)
  490.     {
  491.         if (mNeeds[itr].flags & kISpNeedFlag_Utility) continue;    // we don't autoconfig to utility needs
  492.  
  493.         if (used[itr] && (mNeeds[itr].flags & kISpNeedFlag_NoMultiConfig)) { continue; }
  494.         
  495.         if (mNeeds[itr].theKind != kISpElementKind_Button) { continue; }
  496.  
  497.         switch(mNeeds[itr].theLabel)
  498.         {
  499.             // don't autoconfigure this need
  500.             case kISpElementLabel_Btn_PauseResume:
  501.                 break;        
  502.  
  503.             case kISpElementLabel_Btn_SlideLeft:
  504.             case kISpElementLabel_Btn_TurnLeft:
  505.                 if (mDialogItemToNeedMapping[kDialogItem_StickLeft] == kUnsetIndex)
  506.                 {
  507.                     mDialogItemToNeedMapping[kDialogItem_StickLeft]    = itr;
  508.                     used[itr] = true;
  509.                 }
  510.                 break;
  511.                 
  512.             case kISpElementLabel_Btn_SlideRight:
  513.             case kISpElementLabel_Btn_TurnRight:
  514.                 if (mDialogItemToNeedMapping[kDialogItem_StickRight] == kUnsetIndex)
  515.                 {
  516.                     mDialogItemToNeedMapping[kDialogItem_StickRight]    = itr;
  517.                     used[itr] = true;
  518.                 }
  519.                 break;
  520.                 
  521.             case kISpElementLabel_Btn_MoveForward:
  522.                 if (mDialogItemToNeedMapping[kDialogItem_StickUp] == kUnsetIndex)
  523.                 {
  524.                     mDialogItemToNeedMapping[kDialogItem_StickUp]    = itr;
  525.                     used[itr] = true;
  526.                 }
  527.                 break;
  528.                 
  529.             case kISpElementLabel_Btn_MoveBackward:
  530.                 if (mDialogItemToNeedMapping[kDialogItem_StickDown] == kUnsetIndex)
  531.                 {
  532.                     mDialogItemToNeedMapping[kDialogItem_StickDown]    = itr;
  533.                     used[itr] = true;
  534.                 }
  535.                 break;
  536.  
  537.             case kISpElementLabel_Btn_LookLeft:
  538.                 if (mDialogItemToNeedMapping[kDialogItem_DPadLeft] == kUnsetIndex)
  539.                 {
  540.                     mDialogItemToNeedMapping[kDialogItem_DPadLeft]    = itr;
  541.                     used[itr] = true;
  542.                 }
  543.                 break;
  544.                 
  545.             case kISpElementLabel_Btn_LookRight:
  546.                 if (mDialogItemToNeedMapping[kDialogItem_DPadRight] == kUnsetIndex)
  547.                 {
  548.                     mDialogItemToNeedMapping[kDialogItem_DPadRight]    = itr;
  549.                     used[itr] = true;
  550.                 }
  551.                 break;
  552.             
  553.             case kISpElementLabel_Btn_LookUp:
  554.                 if (mDialogItemToNeedMapping[kDialogItem_DPadUp] == kUnsetIndex)
  555.                 {
  556.                     mDialogItemToNeedMapping[kDialogItem_DPadUp]    = itr;
  557.                     used[itr] = true;
  558.                 }
  559.                 break;
  560.             
  561.             case kISpElementLabel_Btn_LookDown:
  562.                 if (mDialogItemToNeedMapping[kDialogItem_DPadDown] == kUnsetIndex)
  563.                 {
  564.                     mDialogItemToNeedMapping[kDialogItem_DPadDown]    = itr;
  565.                     used[itr] = true;
  566.                 }
  567.                 break;
  568.             
  569.             default:
  570.                 // don't configure axis or delta versions of buttons that did not have direction set
  571.                 // they probably don't make sense for autoconfiguring
  572.                 if ((mNeeds[itr].flags & kISpNeedFlag_Button_AlreadyDelta) ||
  573.                     (mNeeds[itr].flags & kISpNeedFlag_Button_AlreadyAxis) )
  574.                     break;
  575.                 
  576.                 // normal button
  577.                 if (buttonCount < kNumSidewinderButtons)
  578.                 {                            
  579.                     mDialogItemToNeedMapping[kDialogItem_Trigger + buttonCount] = itr;
  580.                     buttonCount++;
  581.                     
  582.                     used[itr] = true;
  583.                 }
  584.                 break;
  585.             }
  586.     }
  587.     
  588.     // set the low level stuff here
  589.     SetVirtualElements();
  590. }
  591.  
  592. OSStatus SidewinderPro::Stop(void)
  593. {
  594.     // need to mark mVirtualElementValid as false first
  595.     mVirtualElementsValid = false;
  596.  
  597.     if (mReferences)  DisposePtr((Ptr) mReferences);    
  598.     mReferences = nil;
  599.     
  600.     if (mNeeds) DisposePtr((Ptr) mNeeds);    
  601.     mNeeds = nil;
  602.     
  603.     return noErr;
  604. }
  605.  
  606. OSStatus SidewinderPro::GetSize(Point &minimum, Point &best)
  607. {
  608.     best.h = minimum.h = 400;
  609.     best.v = minimum.v = 310;
  610.     
  611.     return noErr;
  612. }
  613.  
  614. OSStatus SidewinderPro::HandleEvent(EventRecord &theEvent, Boolean &handled)
  615. {
  616.     theEvent;
  617.     
  618.     handled = false;
  619.         
  620.     UpdateAllButtons();
  621.  
  622.     return noErr;
  623. }
  624.  
  625. OSStatus SidewinderPro::Show(DialogPtr theDialog, short dialogItemNumber, Rect &r)
  626. {
  627.     OSStatus err;
  628.     
  629.     mRect = r;
  630.     
  631.     mDialog = theDialog;
  632.     mBaseDITLCount = CountDITL(theDialog);
  633.  
  634.     // open the resource file and error check
  635.     mResRef = FSpOpenResFile(&mFileSpec, fsRdPerm);
  636.     err = ::ResError();
  637.     WARNING(err == noErr, "SidewinderPro::Show could not FSpOpenResFile on the Sidewinder ResFile");
  638.     if (err != noErr) { return err; }
  639.     
  640.     // get our DITL and error check
  641.     Handle ditl = Get1Resource('DITL', kDITLID_Config);
  642.     err = ::ResError();
  643.     WARNING(err == noErr, "SidewinderPro::Show could not Get1Resource on the Sidewinder DITL");
  644.     if (err != noErr) { CloseResFile(mResRef); return err; }
  645.     
  646.     // append our DITL
  647.     AppendDITL(theDialog, ditl, -dialogItemNumber);
  648.     WARNING(CountDITL(mDialog) > mBaseDITLCount, "SidewinderPro::Show AppendDITL did not increase DITL count");
  649.     
  650.     // free our DITL
  651.     ReleaseResource(ditl);
  652.  
  653.     // setup the checkboxes
  654.     SetDialogControl(kDialogItem_Checkbox_Reverse_StickVertical,    mReverseStickVertical);
  655.     SetDialogControl(kDialogItem_Checkbox_Reverse_HatVertical,        mReverseHatVertical);
  656.     SetDialogControl(kDialogItem_Checkbox_Reverse_Rudder,             mReverseRudder);
  657.     SetDialogControl(kDialogItem_Checkbox_Reverse_Throttle,            mReverseThrottle);
  658.  
  659.     mVisable = true;
  660.  
  661.     // clear out ui indiciators
  662.     for (UInt32 index = 0; index < kDialogItem_NumPopups; index++)
  663.         mPopupPressed[index] = false;
  664.     UpdateAllButtons ();
  665.     
  666.     return noErr;
  667. }
  668.  
  669. OSStatus SidewinderPro::Hide(void)
  670. {
  671.     // restore to original count of items
  672.     ShortenDITL(mDialog, CountDITL(mDialog) - mBaseDITLCount);
  673.     WARNING(CountDITL(mDialog) == mBaseDITLCount, "SidewinderPro::Hide Failed to restore the DITL count");
  674.     
  675.     // mark that we are no longer visable
  676.     mVisable = false;
  677.  
  678.     // clear our mDialog ptr
  679.     mDialog = nil;
  680.  
  681.     // close our res file and assert check
  682.     CloseResFile(mResRef);
  683.     RES_WARNING("SidewinderPro::Hide CloseResFile choked");
  684.     
  685.     return noErr;
  686. }
  687.  
  688. OSStatus SidewinderPro::BeginConfiguration(UInt32 count, ISpNeed needs[])
  689. {
  690.     count;
  691.     needs;
  692.  
  693.     WARNING(mVirtualElementsValid,        "BeginConfiguration was called but the virtual elements were not valid");
  694.  
  695.     return noErr;
  696. }
  697.  
  698. OSStatus SidewinderPro::EndConfiguration(Boolean accept)
  699. {
  700.     accept;
  701.  
  702.     WARNING(mVirtualElementsValid,        "EndConfiguration was called but the virtual elements were not valid");
  703.  
  704.     SetVirtualElements();    
  705.     
  706.     return noErr;
  707. }
  708.  
  709. OSStatus SidewinderPro::SetActive(Boolean active)
  710. {
  711.     if (mActive == active) return noErr;
  712.     
  713.     mActive = active;
  714.     
  715.     // we're responsible for pushing any values which are non-default
  716.     if (mActive) PushAllNonDefaultValues();
  717.     
  718.     return noErr;
  719. }
  720.  
  721. /* =============================================================================
  722.  *        PushAllNonDefaultValues (private)
  723.  *
  724.  *    This is done when activating, as part of our duties as the driver. 
  725.  *
  726.  *    A driver is responsible for pushing all non-default values when it is
  727.  *    activated.
  728.  *
  729.  *    the default values for buttons, dpads, deltas and asymmetric axis is zero
  730.  *    the default value for symmetric axis is kISpAxisMiddle
  731.  *
  732.  * ========================================================================== */
  733. OSStatus SidewinderPro::PushAllNonDefaultValues(void)
  734. {
  735.     AbsoluteTime time = ISpUptime();
  736.     
  737.     // the elements have been reset across suspend, so we need to push anything
  738.     // that is non-default
  739.     SidewinderStateStruct resetState;
  740.     resetState.xAxis        = kISpAxisMiddle;
  741.     resetState.yAxis        = kISpAxisMiddle;
  742.     resetState.throttle        = kISpAxisMinimum;
  743.     resetState.rudder        = kISpAxisMiddle;
  744.     resetState.hat            = kISpPadIdle;
  745.  
  746.     for (UInt32 itr = 0; itr < kNumSidewinderButtons; itr++)
  747.         { resetState.buttons[itr] = kISpButtonUp; }
  748.     
  749.     // push the low level stuff thats different
  750.     
  751.     if (mOldState.xAxis != resetState.xAxis)
  752.         ISpElement_PushSimpleData(mXAxis, mOldState.xAxis, &time);
  753.     if (mOldState.yAxis != resetState.yAxis)
  754.         ISpElement_PushSimpleData(mYAxis, mOldState.yAxis, &time);
  755.     if (mOldState.throttle != resetState.throttle)
  756.         ISpElement_PushSimpleData(mThrottle, mOldState.throttle, &time);
  757.     if (mOldState.rudder != resetState.rudder)
  758.         ISpElement_PushSimpleData(mRudder, mOldState.rudder, &time);
  759.     if (mOldState.hat != resetState.hat)
  760.         ISpElement_PushSimpleData(mHat, mOldState.hat, &time);
  761.  
  762.     // it's better to assume a button was released while we were deactive
  763.     // than to assume that is it still down. Since we have not been getting
  764.     // called to update changes while we were deactivated, we have to
  765.     // assume one or the other
  766.     {
  767.         for (UInt32 itr = 0; itr < kNumSidewinderButtons; itr++)
  768.             mOldState.buttons[itr] = resetState.buttons[itr];
  769.     }
  770.  
  771.     // if high level is inited, push 'new' values to virtual elements also
  772.     if (mVirtualElementsValid)
  773.     {
  774.         // set mOldHLData to reset state
  775.         StateToHighLevelData (resetState, mOldHLData);
  776.         SetAsFields(mOldHLData);
  777.         
  778.         // set new state to the old low level state
  779.         HighLevelData newHLData;
  780.         StateToHighLevelData (mOldState, newHLData);
  781.         SetAsFields(newHLData);
  782.         
  783.         // push the 'new' values
  784.         PushDataToVirtuals(newHLData);
  785.     }
  786.  
  787.     return noErr;
  788. }
  789.  
  790. OSStatus SidewinderPro::GetIcon(short &iconSuiteResourceId)
  791. {
  792.     iconSuiteResourceId = 128;
  793.     
  794.     return 0;
  795. }
  796.  
  797.  
  798. void SidewinderPro::DoReverse(short dialog_item, Boolean &the_boolean)
  799. {
  800.     the_boolean = !the_boolean;
  801.     SetDialogControl(dialog_item, the_boolean);
  802.     mDirty = true;
  803. }
  804.  
  805.  
  806. OSStatus SidewinderPro::DialogItemHit(short itemHit)
  807. {
  808.     short relHit = itemHit - mBaseDITLCount;
  809.     
  810.     switch (relHit)
  811.     {
  812.         case kDialogItem_Checkbox_Reverse_StickVertical:    DoReverse(relHit, mReverseStickVertical);    break;
  813.         case kDialogItem_Checkbox_Reverse_HatVertical:        DoReverse(relHit, mReverseHatVertical);        break;
  814.         case kDialogItem_Checkbox_Reverse_Rudder:            DoReverse(relHit, mReverseRudder);            break;
  815.         case kDialogItem_Checkbox_Reverse_Throttle:         DoReverse(relHit, mReverseThrottle);        break;
  816.     }
  817.     
  818.     return noErr;
  819. }
  820.  
  821.  
  822. OSStatus SidewinderPro::GetState(UInt32 buflen, void *buffer, UInt32 &length)
  823. {
  824.     WARNING(mVirtualElementsValid,                "SidewinderPro: GetState was called but the virtual elemtns were not valid");
  825.     WARNING((buflen == 0) || (buffer != nil),    "SidewinderPro: GetState buffer == nil");
  826.     
  827.     MicrosoftSetVersion1 *set_vers1_ptr = (MicrosoftSetVersion1 *) buffer;
  828.     length = sizeof(MicrosoftSetVersion1);
  829.  
  830.     if (length > buflen) { return noErr; }    // required length > space in the buffer, return
  831.     
  832.     UInt32 itr;
  833.     set_vers1_ptr->version = kSetVersion1;
  834.  
  835.     for(itr = 1; itr <= kDialogItem_NumPopups; itr++)
  836.     {
  837.         set_vers1_ptr->mapping[itr - 1] = mDialogItemToNeedMapping[itr]; // set is zero based array
  838.     }
  839.     
  840.     set_vers1_ptr->flags = 0;
  841.     
  842.     if (mReverseStickVertical)    { set_vers1_ptr->flags |= kSetReverseStickVertical; }
  843.     if (mReverseHatVertical)    { set_vers1_ptr->flags |= kSetReverseHatVertical; }
  844.     if (mReverseRudder)            { set_vers1_ptr->flags |= kSetReverseRudder; }
  845.     if (mReverseThrottle)        { set_vers1_ptr->flags |= kSetReverseThrottle; }
  846.     
  847.     return noErr;
  848. }
  849.  
  850. OSStatus SidewinderPro::SetState(UInt32 length, void *buffer)
  851. {
  852.     WARNING(mVirtualElementsValid,                "SetState was called but the virtual elements were not valid");
  853.     WARNING((length == 0) || (buffer != nil),    "SidewinderPro: SetState buffer == nil");
  854.     WARNING((length > 4),                        "SidewinderPro: SetState length < 4");
  855.  
  856.     UInt32 itr;
  857.     
  858.     // min size check
  859.     if (length < 4) { return -1;} 
  860.  
  861.     UInt32 version = * ((UInt32 *) buffer);
  862.     
  863.     switch(version)
  864.     {
  865.         case kSetVersion1:
  866.             if (length == sizeof(MicrosoftSetVersion1))
  867.             {
  868.                 MicrosoftSetVersion1 *set_vers1_ptr = (MicrosoftSetVersion1 *) buffer;
  869.                 
  870.                 for(itr = 1; itr <= kDialogItem_NumPopups; itr++)
  871.                 {
  872.                     mDialogItemToNeedMapping[itr] = set_vers1_ptr->mapping[itr - 1]; // set is zero based array
  873.                 }
  874.                 
  875.                 mReverseStickVertical    = (set_vers1_ptr->flags & kSetReverseStickVertical)    > 0;
  876.                 mReverseHatVertical        = (set_vers1_ptr->flags & kSetReverseHatVertical)    > 0;
  877.                 mReverseRudder            = (set_vers1_ptr->flags & kSetReverseRudder)        > 0;
  878.                 mReverseThrottle        = (set_vers1_ptr->flags & kSetReverseThrottle)        > 0;
  879.             }
  880.         break;
  881.     }
  882.  
  883.     SetVirtualElements();
  884.     
  885.     if (mVisable)
  886.     {
  887.         Draw ();
  888.             
  889.         SetDialogControl(kDialogItem_Checkbox_Reverse_StickVertical,    mReverseStickVertical);
  890.         SetDialogControl(kDialogItem_Checkbox_Reverse_HatVertical,        mReverseHatVertical);
  891.         SetDialogControl(kDialogItem_Checkbox_Reverse_Rudder,            mReverseRudder);
  892.         SetDialogControl(kDialogItem_Checkbox_Reverse_Throttle,            mReverseThrottle);
  893.     }
  894.     
  895.     mDirty = false;
  896.     
  897.     return noErr;
  898. }
  899.  
  900. OSStatus SidewinderPro::Tickle(void)
  901. {
  902.     return noErr;
  903. }
  904.  
  905. void SidewinderPro::SetAsFields(HighLevelData ¤t)
  906. {
  907.     AxisToButtons(current.xAxis, current.xAxis_as_buttons);
  908.     AxisToButtons(current.yAxis, current.yAxis_as_buttons);
  909.     AxisToButtons(current.throttle, current.throttle_as_buttons);
  910.     AxisToButtons(current.rudder, current.rudder_as_buttons);
  911.  
  912.     DPadToButtonsAndAxis(current.hat, current.hat_as_buttons, current.hat_as_axis);
  913. }
  914.  
  915. void SidewinderPro::PushDataToVirtuals(HighLevelData ¤t)
  916. {
  917.     WARNING(mVirtualElementsValid,    "PushDataToVirtuals mVirtualElementsValid was false");
  918.  
  919.     OSStatus err;
  920.     AbsoluteTime time = ISpUptime();
  921.     
  922.     // x and y axis
  923.     if (((current.xAxis != mOldHLData.xAxis) || (current.yAxis != mOldHLData.yAxis)) && (mVirtuals.stickMovement || mVirtuals.stickDPad))
  924.     {
  925.         ISpMovementData    moveData;
  926.         
  927.         moveData.xAxis = current.xAxis;
  928.         moveData.yAxis = current.yAxis;
  929.         
  930.         moveData.direction = AxisToDPad(moveData.xAxis, moveData.yAxis);
  931.         
  932.         if (mVirtuals.stickMovement != nil)
  933.         {
  934.             err = ISpElement_PushComplexData(mVirtuals.stickMovement, sizeof (moveData), &moveData, &time);
  935.             WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  936.         }
  937.         
  938.         if (mVirtuals.stickDPad != nil)
  939.         {
  940.             err = ISpElement_PushSimpleData(mVirtuals.stickDPad, moveData.direction, &time);
  941.             WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  942.         }
  943.     }
  944.     
  945.     // *************** X AXIS ***************
  946.     if ((current.xAxis != mOldHLData.xAxis) && (mVirtuals.xAxis != nil))
  947.     {
  948.         err = ISpElement_PushSimpleData(mVirtuals.xAxis, current.xAxis, &time);
  949.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  950.     }
  951.     
  952.     if ((current.xAxis_as_buttons[0] != mOldHLData.xAxis_as_buttons[0]) && (mVirtuals.xAxis_as_buttons[0] != nil))
  953.     {
  954.         err = ISpElement_PushSimpleData(mVirtuals.xAxis_as_buttons[0], current.xAxis_as_buttons[0], &time);
  955.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  956.     }
  957.     
  958.     if ((current.xAxis_as_buttons[1] != mOldHLData.xAxis_as_buttons[1]) && (mVirtuals.xAxis_as_buttons[1] != nil))
  959.     {
  960.         err = ISpElement_PushSimpleData(mVirtuals.xAxis_as_buttons[1], current.xAxis_as_buttons[1], &time);
  961.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  962.     }
  963.  
  964.     // *************** Y AXIS ***************
  965.     if ((current.yAxis != mOldHLData.yAxis) && (mVirtuals.yAxis != nil))
  966.     {
  967.         err = ISpElement_PushSimpleData(mVirtuals.yAxis, current.yAxis, &time);
  968.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  969.     }
  970.     
  971.     if ((current.yAxis_as_buttons[0] != mOldHLData.yAxis_as_buttons[0]) && (mVirtuals.yAxis_as_buttons[0] != nil))
  972.     {
  973.         err = ISpElement_PushSimpleData(mVirtuals.yAxis_as_buttons[0], current.yAxis_as_buttons[0], &time);
  974.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  975.     }
  976.     
  977.     if ((current.yAxis_as_buttons[1] != mOldHLData.yAxis_as_buttons[1]) && (mVirtuals.yAxis_as_buttons[1] != nil))
  978.     {
  979.         err = ISpElement_PushSimpleData(mVirtuals.yAxis_as_buttons[1], current.yAxis_as_buttons[1], &time);
  980.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  981.     }
  982.  
  983.     // *************** THROTTLE ***************
  984.     if ((current.throttle != mOldHLData.throttle) && (mVirtuals.throttle != nil))
  985.     {
  986.         err = ISpElement_PushSimpleData(mVirtuals.throttle, current.throttle, &time);
  987.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  988.     }
  989.     
  990.     if ((current.throttle_as_buttons[0] != mOldHLData.throttle_as_buttons[0]) && (mVirtuals.throttle_as_buttons[0] != nil))
  991.     {
  992.         err = ISpElement_PushSimpleData(mVirtuals.throttle_as_buttons[0], current.throttle_as_buttons[0], &time);
  993.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  994.     }
  995.     
  996.     if ((current.throttle_as_buttons[1] != mOldHLData.throttle_as_buttons[1]) && (mVirtuals.throttle_as_buttons[1] != nil))
  997.     {
  998.         err = ISpElement_PushSimpleData(mVirtuals.throttle_as_buttons[1], current.throttle_as_buttons[1], &time);
  999.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  1000.     }
  1001.  
  1002.     // *************** RUDDER ***************
  1003.     if ((current.rudder != mOldHLData.rudder) && (mVirtuals.rudder != nil))
  1004.     {
  1005.         err = ISpElement_PushSimpleData(mVirtuals.rudder, current.rudder, &time);
  1006.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  1007.     }
  1008.     
  1009.     if ((current.rudder_as_buttons[0] != mOldHLData.rudder_as_buttons[0]) && (mVirtuals.rudder_as_buttons[0] != nil))
  1010.     {
  1011.         err = ISpElement_PushSimpleData(mVirtuals.rudder_as_buttons[0], current.rudder_as_buttons[0], &time);
  1012.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  1013.     }
  1014.     
  1015.     if ((current.rudder_as_buttons[1] != mOldHLData.rudder_as_buttons[1]) && (mVirtuals.rudder_as_buttons[1] != nil))
  1016.     {
  1017.         err = ISpElement_PushSimpleData(mVirtuals.rudder_as_buttons[1], current.rudder_as_buttons[1], &time);
  1018.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  1019.     }
  1020.  
  1021.     // *************** DPAD ***************
  1022.     if ((current.hat != mOldHLData.hat) && (mVirtuals.hat != nil))
  1023.     {
  1024.         err = ISpElement_PushSimpleData(mVirtuals.hat, current.hat, &time);
  1025.         WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  1026.     }
  1027.     
  1028.     UInt32 hat_button_itr;
  1029.     for(hat_button_itr = 0; hat_button_itr < 4; hat_button_itr++)
  1030.     {
  1031.         ISpElementReference this_hat_button_element = mVirtuals.hat_as_buttons[hat_button_itr];
  1032.         UInt32 cur_hat_button_data = current.hat_as_buttons[hat_button_itr];
  1033.         UInt32 old_hat_button_data = mOldHLData.hat_as_buttons[hat_button_itr];
  1034.         
  1035.         if ((cur_hat_button_data != old_hat_button_data) && (this_hat_button_element != nil))
  1036.         {
  1037.             err = ISpElement_PushSimpleData(this_hat_button_element, cur_hat_button_data, &time);
  1038.             WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  1039.         }
  1040.     }
  1041.     
  1042.     Boolean    axisDataChanged = false;
  1043.     
  1044.     UInt32 hat_axis_itr;
  1045.     for(hat_axis_itr = 0; hat_axis_itr < 2; hat_axis_itr++)
  1046.     {
  1047.         ISpElementReference this_hat_axis_element = mVirtuals.hat_as_axis[hat_axis_itr];
  1048.         UInt32 cur_hat_axis_data = current.hat_as_axis[hat_axis_itr];
  1049.         UInt32 old_hat_axis_data = mOldHLData.hat_as_axis[hat_axis_itr];
  1050.         
  1051.         if (cur_hat_axis_data != old_hat_axis_data)
  1052.         {
  1053.             axisDataChanged = true;
  1054.             
  1055.             if (this_hat_axis_element != nil)
  1056.             {
  1057.                 err = ISpElement_PushSimpleData(this_hat_axis_element, cur_hat_axis_data, &time);
  1058.                 WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  1059.             }
  1060.         }
  1061.     }
  1062.  
  1063.     if (axisDataChanged && mVirtuals.hat_as_movement)
  1064.     {
  1065.         ISpMovementData    moveData;
  1066.         
  1067.         moveData.xAxis = current.hat_as_axis[0];
  1068.         moveData.yAxis = current.hat_as_axis[1];
  1069.         
  1070.         moveData.direction = current.hat;
  1071.         
  1072.         if (mVirtuals.hat_as_movement != nil)
  1073.         {
  1074.             err = ISpElement_PushComplexData(mVirtuals.hat_as_movement, sizeof (moveData), &moveData, &time);
  1075.             WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  1076.         }
  1077.     }
  1078.     
  1079.     // *************** BUTTONS ***************
  1080.     UInt32 button_itr;
  1081.     for(button_itr = 0; button_itr < kNumSidewinderButtons; button_itr++)
  1082.     {
  1083.         if ((current.buttons[button_itr] != mOldHLData.buttons[button_itr]) && (mVirtuals.buttons[button_itr] != nil))
  1084.         {
  1085.             err = ISpElement_PushSimpleData(mVirtuals.buttons[button_itr], current.buttons[button_itr], &time);
  1086.             WARNING(err == noErr,    "SidewinderPro::PushDataToVirtuals ISpElement_PushSimpleData failed");
  1087.         }
  1088.     }
  1089. }
  1090.  
  1091. OSStatus SidewinderPro::InterruptTickle(void)
  1092. {    
  1093.     return noErr;
  1094. }
  1095.  
  1096. OSStatus SidewinderPro::Draw(void)
  1097. {
  1098.     Str255 titleStr;
  1099.     Rect titleRect;
  1100.  
  1101.     GetIndString (titleStr, kStrList_Main, kStrList_Main_Stick);
  1102.     DialogItem_GetRect(mDialog, mBaseDITLCount + kDialogItem_GroupBox_Stick, &titleRect);
  1103.     GScGroupBox_SecondaryNamed_Draw(&titleRect, titleStr, kGSActive);
  1104.  
  1105.     GetIndString (titleStr, kStrList_Main, kStrList_Main_POVHat);
  1106.     DialogItem_GetRect(mDialog, mBaseDITLCount + kDialogItem_GroupBox_POVHat, &titleRect);
  1107.     GScGroupBox_SecondaryNamed_Draw(&titleRect, titleStr, kGSActive);
  1108.  
  1109.     GetIndString (titleStr, kStrList_Main, kStrList_Main_Throttle);
  1110.     DialogItem_GetRect(mDialog, mBaseDITLCount + kDialogItem_GroupBox_Throttle, &titleRect);
  1111.     GScGroupBox_SecondaryNamed_Draw(&titleRect, titleStr, kGSActive);
  1112.  
  1113.     GetIndString (titleStr, kStrList_Main, kStrList_Main_Rudder);
  1114.     DialogItem_GetRect(mDialog, mBaseDITLCount + kDialogItem_GroupBox_Rudder, &titleRect);
  1115.     GScGroupBox_SecondaryNamed_Draw(&titleRect, titleStr, kGSActive);
  1116.  
  1117.     GetIndString (titleStr, kStrList_Main, kStrList_Main_StickButtons);
  1118.     DialogItem_GetRect(mDialog, mBaseDITLCount + kDialogItem_GroupBox_StickButtons, &titleRect);
  1119.     GScGroupBox_SecondaryNamed_Draw(&titleRect, titleStr, kGSActive);
  1120.  
  1121.     GetIndString (titleStr, kStrList_Main, kStrList_Main_BaseButtons);
  1122.     DialogItem_GetRect(mDialog, mBaseDITLCount + kDialogItem_GroupBox_BaseButtons, &titleRect);
  1123.     GScGroupBox_SecondaryNamed_Draw(&titleRect, titleStr, kGSActive);
  1124.  
  1125.     for(UInt32 itr = kDialogItem_FirstPopup; itr <= kDialogItem_NumPopups; itr++)
  1126.         { PlotPopupIcon(itr + mBaseDITLCount, ttNone);    }
  1127.     
  1128.     return noErr;
  1129. }
  1130.  
  1131. OSStatus SidewinderPro::Click(const EventRecord &event)
  1132. {
  1133.     // Find the point in local coords
  1134.     Point where;
  1135.     where = event.where;
  1136.     GlobalToLocal(&where);
  1137.  
  1138.     UInt32 itr;
  1139.  
  1140.     for(itr = kDialogItem_FirstPopup; itr <= kDialogItem_NumPopups; itr++)
  1141.     {
  1142.         short itemNo = itr + mBaseDITLCount;
  1143.         UInt32 oldNeed = mDialogItemToNeedMapping[itr];
  1144.         UInt32 newNeed;
  1145.         
  1146.         switch (itr)
  1147.         {
  1148.             case kDialogItem_StickUp:
  1149.             case kDialogItem_StickDown:
  1150.                 HandleStickClick (where, itemNo, kDialogItem_StickUp, kDialogItem_StickDown, 
  1151.                     kDialogItem_StickLeft, kDialogItem_StickRight, oldNeed, newNeed);
  1152.                 break;
  1153.                 
  1154.             case kDialogItem_StickLeft:
  1155.             case kDialogItem_StickRight:
  1156.                 HandleStickClick (where, itemNo, kDialogItem_StickUp, kDialogItem_StickDown, 
  1157.                     kDialogItem_StickLeft, kDialogItem_StickRight, oldNeed, newNeed);
  1158.                 break;
  1159.                 
  1160.             case kDialogItem_ThrottleLower:
  1161.             case kDialogItem_ThrottleHigher:
  1162.                 HandleAxisClick (where, itemNo, kISpElementLabel_Axis_Throttle, kDialogItem_ThrottleLower, kDialogItem_ThrottleHigher, oldNeed, newNeed);
  1163.                 break;
  1164.  
  1165.             case kDialogItem_RudderLeft:
  1166.             case kDialogItem_RudderRight:
  1167.                 HandleAxisClick (where, itemNo, kISpElementLabel_Axis_Rudder, kDialogItem_RudderLeft, kDialogItem_RudderRight, oldNeed, newNeed);
  1168.                 break;
  1169.             
  1170.             case kDialogItem_Trigger:
  1171.                     HandleButtonClick (where, itemNo, kISpElementLabel_Btn_Fire, oldNeed, newNeed);
  1172.                 break;
  1173.                 
  1174.  
  1175.             case kDialogItem_TopButton:
  1176.             case kDialogItem_StickHighButton:
  1177.             case kDialogItem_StickLowButton:
  1178.             case kDialogItem_BaseFarLeft:
  1179.             case kDialogItem_BaseFarRight:
  1180.             case kDialogItem_BaseNearLeft:
  1181.             case kDialogItem_BaseNearRight:
  1182.                     HandleButtonClick (where, itemNo, kISpElementLabel_None, oldNeed, newNeed);
  1183.                 break;
  1184.  
  1185.             case kDialogItem_DPadUp:
  1186.             case kDialogItem_DPadLeft:
  1187.             case kDialogItem_DPadDown:
  1188.             case kDialogItem_DPadRight:
  1189.                     HandleDPadClick (where, itemNo,
  1190.                         kDialogItem_DPadUp, kDialogItem_DPadDown, 
  1191.                         kDialogItem_DPadLeft, kDialogItem_DPadRight, oldNeed, newNeed);
  1192.                 break;
  1193.  
  1194.             default:
  1195.                 break;
  1196.         }        
  1197.     }
  1198.     
  1199.     return noErr;
  1200. }
  1201.  
  1202.  
  1203. OSStatus SidewinderPro::ADBReInit(Boolean inPostProcess)
  1204. {
  1205.     UInt32 itr;
  1206.     
  1207.     switch(inPostProcess)
  1208.     {
  1209.         case false:
  1210.             // remember if we must patch
  1211.             mMustRestorePatch = mPatched;
  1212.             
  1213.             // if required unpatch
  1214.             if (mPatched) { Unpatch(); }
  1215.             
  1216.             // clear our adb address
  1217.             mADBAddress = 16;
  1218.             
  1219.             // zero the device table
  1220.             for(itr = 0; itr < 16; itr++) { gSidewinders[itr] = nil; }
  1221.             
  1222.             // make us an orphan
  1223.             mOrphan = true;
  1224.         break;
  1225.         
  1226.         case true:
  1227.             UInt32 deviceTableIndex;            
  1228.             for (deviceTableIndex = CountADBs(); deviceTableIndex > 0; deviceTableIndex--)
  1229.             {    
  1230.                 ADBDataBlock     adbDataBlock;            // data block for the device refered to by device_table_index
  1231.                 ADBAddress         adbAddress;                // adb address for the device refered to by device_table_index
  1232.                 Boolean            isSideWinder;
  1233.                 
  1234.                 // is this device table index a sidewinder ?
  1235.                 isSideWinder = IsSideWinder(deviceTableIndex);
  1236.  
  1237.                 // not a sidewinder, skip it
  1238.                 if (!isSideWinder) { continue; }
  1239.                 
  1240.                 // get this adb address
  1241.                 adbAddress = GetIndADB(&adbDataBlock, deviceTableIndex);
  1242.                                 
  1243.                 // this sidewinder is in use already
  1244.                 if (gSidewinders[adbAddress] != nil)    { continue; }
  1245.  
  1246.                 // this is a sidewinder pro and an empty slot
  1247.                 // take it and break out (one slot per customer)
  1248.                 mADBAddress = adbAddress;
  1249.                 gSidewinders[adbAddress] = this;
  1250.                 mOrphan = false;
  1251.                 break;
  1252.             }
  1253.             
  1254.             if (mOrphan)
  1255.             {
  1256.                 for(itr = 0; itr < 16; itr++)
  1257.                 {
  1258.                     // this sidewinder is in use already
  1259.                     if (gSidewinders[itr] != nil) { continue; }
  1260.  
  1261.                     // this is an empty slot
  1262.                     // take it and break out (one slot per customer)
  1263.                     mADBAddress                    = 16;        // invalid
  1264.                     gSidewinders[itr]            = this;
  1265.                     mOrphan                        = true;
  1266.                     break;
  1267.                 }
  1268.             }
  1269.             
  1270.             if (mMustRestorePatch) { Patch(); }
  1271.             
  1272.         break;
  1273.     }
  1274.  
  1275.     return noErr;
  1276. }
  1277.  
  1278. /*
  1279.  *
  1280.  * SetVirtualElements
  1281.  *
  1282.  * This function takes the virtual index stuff and sets our virtual elements;
  1283.  *
  1284.  */
  1285.  
  1286. void SidewinderPro::SetVirtualElements(void)
  1287. {
  1288.     WARNING(mNeeds != nil,                        "SidewinderPro::SetVirtualElements but mNeeds was nil");
  1289.     WARNING(mReferences != nil,                    "SidewinderPro::SetVirtualElements but mReferences was nil");
  1290.     WARNING(mDialogItemToNeedMapping != nil,    "SidewinderPro::SetVirtualElements but mDialogItemToNeedMapping was nil");
  1291.  
  1292. #if DEBUG
  1293.     {
  1294.         UInt32 debug_mapping_itr;
  1295.         
  1296.         for(debug_mapping_itr = 0; debug_mapping_itr < kDialogItem_NumPopups+1; debug_mapping_itr++)
  1297.         {
  1298.             UInt32 debug_mapping = mDialogItemToNeedMapping[debug_mapping_itr];
  1299.             WARNING(((debug_mapping == kUnsetIndex) || (debug_mapping < mNumNeeds)),    "SidewinderPro::SetVirtualElements out of range");
  1300.         }
  1301.     }    
  1302. #endif
  1303.  
  1304.     ClearVirtuals();
  1305.     
  1306.     UInt32    need;
  1307.     
  1308.     // stick up: up button, y axis and movement
  1309.     need = mDialogItemToNeedMapping[kDialogItem_StickUp];
  1310.     if (need != kUnsetIndex)
  1311.         {
  1312.         switch (mNeeds[need].theKind)
  1313.             {
  1314.             case kISpElementKind_Movement:    mVirtuals.stickMovement = mReferences[need]; break;
  1315.             case kISpElementKind_DPad:        mVirtuals.stickDPad = mReferences[need]; break;
  1316.             case kISpElementKind_Axis:        mVirtuals.yAxis = mReferences[need]; break;
  1317.             case kISpElementKind_Button:    mVirtuals.yAxis_as_buttons[1] = mReferences[need];    break;
  1318.             }
  1319.         }
  1320.         
  1321.     // stick down: down button
  1322.     need = mDialogItemToNeedMapping[kDialogItem_StickDown];
  1323.     if (need != kUnsetIndex)
  1324.         {
  1325.         switch (mNeeds[need].theKind)
  1326.             {
  1327.             case kISpElementKind_Button:    mVirtuals.yAxis_as_buttons[0] = mReferences[need];    break;
  1328.             }
  1329.         }
  1330.         
  1331.     // stick left: left button and x axis
  1332.     need = mDialogItemToNeedMapping[kDialogItem_StickLeft];
  1333.     if (need != kUnsetIndex)
  1334.         {
  1335.         switch (mNeeds[need].theKind)
  1336.             {
  1337.             case kISpElementKind_Axis:        mVirtuals.xAxis = mReferences[need]; break;
  1338.             case kISpElementKind_Button:    mVirtuals.xAxis_as_buttons[0] = mReferences[need];    break;
  1339.             }
  1340.         }
  1341.         
  1342.     // stick right: right button
  1343.     need = mDialogItemToNeedMapping[kDialogItem_StickRight];
  1344.     if (need != kUnsetIndex)
  1345.         {
  1346.         switch (mNeeds[need].theKind)
  1347.             {
  1348.             case kISpElementKind_Button:        mVirtuals.xAxis_as_buttons[1] = mReferences[need];    break;
  1349.             }
  1350.         }
  1351.                 
  1352.     // throttle lower: min button and throttle axis
  1353.     need = mDialogItemToNeedMapping[kDialogItem_ThrottleLower];
  1354.     if (need != kUnsetIndex)
  1355.         {
  1356.         switch (mNeeds[need].theKind)
  1357.             {
  1358.             case kISpElementKind_Axis:            mVirtuals.throttle = mReferences[need]; break;
  1359.             case kISpElementKind_Button:        mVirtuals.throttle_as_buttons[0] = mReferences[need];    break;
  1360.             }
  1361.         }
  1362.         
  1363.     // throttle higher: max button
  1364.     need = mDialogItemToNeedMapping[kDialogItem_ThrottleHigher];
  1365.     if (need != kUnsetIndex)
  1366.         {
  1367.         switch (mNeeds[need].theKind)
  1368.             {
  1369.             case kISpElementKind_Button:        mVirtuals.throttle_as_buttons[1] = mReferences[need];    break;
  1370.             }
  1371.         }
  1372.         
  1373.     // rudder lower: min button and rudder axis
  1374.     need = mDialogItemToNeedMapping[kDialogItem_RudderLeft];
  1375.     if (need != kUnsetIndex)
  1376.         {
  1377.         switch (mNeeds[need].theKind)
  1378.             {
  1379.             case kISpElementKind_Axis:            mVirtuals.rudder = mReferences[need]; break;
  1380.             case kISpElementKind_Button:        mVirtuals.rudder_as_buttons[0] = mReferences[need];    break;
  1381.             }
  1382.         }
  1383.         
  1384.     // rudder higher: max button
  1385.     need = mDialogItemToNeedMapping[kDialogItem_RudderRight];
  1386.     if (need != kUnsetIndex)
  1387.         {
  1388.         switch (mNeeds[need].theKind)
  1389.             {
  1390.             case kISpElementKind_Button:        mVirtuals.rudder_as_buttons[1] = mReferences[need];    break;
  1391.             }
  1392.         }
  1393.         
  1394.     // hat up: up button, y axis, movement, hat
  1395.     need = mDialogItemToNeedMapping[kDialogItem_DPadUp];
  1396.     if (need != kUnsetIndex)
  1397.         {
  1398.         switch (mNeeds[need].theKind)
  1399.             {
  1400.             case kISpElementKind_DPad:            mVirtuals.hat = mReferences[need]; break;
  1401.             case kISpElementKind_Movement:        mVirtuals.hat_as_movement = mReferences[need]; break;
  1402.             case kISpElementKind_Axis:            mVirtuals.hat_as_axis[1] = mReferences[need]; break;
  1403.             case kISpElementKind_Button:        mVirtuals.hat_as_buttons[0] = mReferences[need];    break;
  1404.             }
  1405.         }
  1406.         
  1407.     // hat down: down button
  1408.     need = mDialogItemToNeedMapping[kDialogItem_DPadDown];
  1409.     if (need != kUnsetIndex)
  1410.         {
  1411.         switch (mNeeds[need].theKind)
  1412.             {
  1413.             case kISpElementKind_Button:        mVirtuals.hat_as_buttons[2] = mReferences[need];    break;
  1414.             }
  1415.         }
  1416.         
  1417.     // hat left: left button and x axis
  1418.     need = mDialogItemToNeedMapping[kDialogItem_DPadLeft];
  1419.     if (need != kUnsetIndex)
  1420.         {
  1421.         switch (mNeeds[need].theKind)
  1422.             {
  1423.             case kISpElementKind_Axis:            mVirtuals.hat_as_axis[0] = mReferences[need]; break;
  1424.             case kISpElementKind_Button:        mVirtuals.hat_as_buttons[1] = mReferences[need];    break;
  1425.             }
  1426.         }
  1427.         
  1428.     // hat right: right button
  1429.     need = mDialogItemToNeedMapping[kDialogItem_DPadRight];
  1430.     if (need != kUnsetIndex)
  1431.         {
  1432.         switch (mNeeds[need].theKind)
  1433.             {
  1434.             case kISpElementKind_Button:        mVirtuals.hat_as_buttons[3] = mReferences[need];    break;
  1435.             }
  1436.         }
  1437.         
  1438.     // buttons
  1439.     for (UInt32 button_itr = 0; button_itr < kNumSidewinderButtons; button_itr++)
  1440.     {
  1441.         need = mDialogItemToNeedMapping[kDialogItem_Trigger + button_itr];
  1442.         
  1443.         if (need != kUnsetIndex)
  1444.             { mVirtuals.buttons[button_itr] = mReferences[need]; }
  1445.     }
  1446. }
  1447.  
  1448. void SidewinderPro::ClearVirtuals (void)
  1449. {
  1450.     mVirtuals.xAxis = nil;
  1451.     mVirtuals.yAxis = nil;
  1452.     mVirtuals.throttle = nil;
  1453.     mVirtuals.rudder = nil;
  1454.  
  1455.     mVirtuals.stickMovement = nil;
  1456.     mVirtuals.stickDPad = nil;
  1457.         
  1458.     mVirtuals.xAxis_as_buttons[0] = nil;
  1459.     mVirtuals.yAxis_as_buttons[0] = nil;
  1460.     mVirtuals.throttle_as_buttons[0] = nil;
  1461.     mVirtuals.rudder_as_buttons[0] = nil;
  1462.  
  1463.     mVirtuals.xAxis_as_buttons[1] = nil;
  1464.     mVirtuals.yAxis_as_buttons[1] = nil;
  1465.     mVirtuals.throttle_as_buttons[1] = nil;
  1466.     mVirtuals.rudder_as_buttons[1] = nil;
  1467.  
  1468.     mVirtuals.hat = nil;
  1469.     mVirtuals.hat_as_movement = nil;
  1470.     mVirtuals.hat_as_buttons[0] = nil;
  1471.     mVirtuals.hat_as_buttons[1] = nil;
  1472.     mVirtuals.hat_as_buttons[2] = nil;
  1473.     mVirtuals.hat_as_buttons[3] = nil;
  1474.     mVirtuals.hat_as_axis[0] = nil;
  1475.     mVirtuals.hat_as_axis[1] = nil;
  1476.     
  1477.     // buttons
  1478.     UInt32 button_itr;    
  1479.     for(button_itr = 0; button_itr < kNumSidewinderButtons; button_itr++)
  1480.     {
  1481.         mVirtuals.buttons[button_itr] = nil;
  1482.     }
  1483. }
  1484.  
  1485.  
  1486. OSStatus SidewinderPro::Initialize(FSSpec fileSpec)
  1487. {
  1488.     OSStatus            err;                        
  1489.     UInt32                count = 0;                            // number of sidewinders
  1490.     short                resource_ref = -1;                    // ref to our resource file
  1491.     Boolean                resource_file_open = false;            // true if our resource file is open, (we open if we find a device)
  1492.         
  1493.     UInt32             device_table_index;        // used w/ CountADBs and GetIndADB starts at the top counts down
  1494.     
  1495.     for (device_table_index = CountADBs(); device_table_index > 0; device_table_index--)
  1496.     {    
  1497.         ADBDataBlock     adbDataBlock;            // data block for the device refered to by device_table_index
  1498.         ADBAddress         adbAddress;                // adb address for the device refered to by device_table_index
  1499.         Boolean            isSideWinder;
  1500.         
  1501.         isSideWinder = IsSideWinder(device_table_index);
  1502.         if (!isSideWinder) { continue; }
  1503.         
  1504.         // get information for this adb address
  1505.         adbAddress = GetIndADB(&adbDataBlock, device_table_index);
  1506.             
  1507.         // open the resource file and check for errors
  1508.         if (!resource_file_open)
  1509.         { 
  1510.             resource_ref         = FSpOpenResFile(&fileSpec, fsRdPerm);
  1511.             err                 = ResError();
  1512.  
  1513.             // assert and error check
  1514.             WARNING(err == noErr, "SidewinderPro::Initialize failed to open res file");
  1515.             if (err != noErr)  { return err; }
  1516.             
  1517.             resource_file_open    = true;                                        // used to know to close res file
  1518.         }
  1519.     
  1520.         // this is a sidewinder pro, create the device
  1521.         gSidewinders[adbAddress] =  new SidewinderPro(adbAddress, fileSpec);
  1522.  
  1523.         // assert and error check
  1524.         WARNING(gSidewinders[adbAddress] != nil,    "SidewinderPro failed to allocate");
  1525.         
  1526.         
  1527.         // increment our count
  1528.         count++;
  1529.     }
  1530.             
  1531.     // if needed close the resource file
  1532.     if (resource_file_open) { CloseResFile(resource_ref); }
  1533.     
  1534.     return noErr;
  1535. }
  1536.  
  1537. Boolean SidewinderPro::IsSideWinder(short inDeviceTableIndex)
  1538. {
  1539.     const char            kSidewinderProOrigAddress = 4;        // original address
  1540.     ADBDataBlock     adbDataBlock;            // data block for the device refered to by device_table_index
  1541.     ADBAddress         adbAddress;                // adb address for the device refered to by device_table_index
  1542.  
  1543.     // get information for this adb address
  1544.     adbAddress = GetIndADB(&adbDataBlock, inDeviceTableIndex);
  1545.     
  1546.     // correct original address ?        
  1547.     if (adbDataBlock.origADBAddr != kSidewinderProOrigAddress)
  1548.         { return false; }
  1549.  
  1550.     // read reg 3 to determine handler id
  1551.     UInt8 register_three[9];
  1552.     ADBOp_TalkSync(adbAddress, 3, register_three);
  1553.  
  1554.     // does register 3 have a valid length ?
  1555.     if (register_three[0] != 2)
  1556.         { return false; }
  1557.             
  1558.     // is handler id correct ?
  1559.     if (register_three[2] != kHandlerID_Addr4_Sidewinder3DPro)
  1560.         { return false; }
  1561.         
  1562.     // passed all the checks must be a sidewinder
  1563.     return true;
  1564. }
  1565.  
  1566. /* =============================================================================
  1567.  *        Terminate (public, static)
  1568.  *
  1569.  *    Gets rid of all our devices.
  1570.  * ========================================================================== */
  1571. void SidewinderPro::Terminate(
  1572.     void)
  1573. {
  1574.     ADBAddress itr;
  1575.     
  1576.     // get rid of all the SidewinderPro devices
  1577.     for(itr = 0; itr < 15; itr++)
  1578.     {
  1579.         if (gSidewinders[itr] != nil) { delete gSidewinders[itr]; }
  1580.     }
  1581. }
  1582.  
  1583.  
  1584. void SidewinderPro::ParseData(
  1585.     void                    *inBuffer,
  1586.     UInt32                    inCommand)
  1587. {
  1588.     OSStatus err;
  1589.     const UInt8 kHiNibble = 0x10 | 0x20 | 0x40 | 0x80;
  1590.     const UInt8 kLoNibble = 0x01 | 0x02 | 0x04 | 0x08;
  1591.     
  1592.     if (mActive && (inCommand & 0x0F) == 0x0C)
  1593.     {
  1594.         AbsoluteTime time = ISpUptime();
  1595.         
  1596.         // Parse the data from "Talk R0" -- xy deltas and buttons
  1597.         UInt8* buffer = (UInt8*) inBuffer;
  1598.         SidewinderStateStruct state;
  1599.         
  1600.         if (buffer[0] != 7) { return; }
  1601.         
  1602.         // parse the raw axis packets
  1603.         state.xAxis     = ((buffer[1] & kLoNibble)    << 6)         | (buffer[2] >> 2);    // 4 + 6 = 10 bits of x
  1604.         state.yAxis     = ((buffer[2] & 0x03)         << 8)         | buffer[3];        // 2 + 8 = 10 bits of y
  1605.         state.throttle    = ((buffer[6] & 0x03)        << 8)        | buffer[7];        // 2 + 8 = 10 bits of throttle
  1606.         state.rudder     = ((buffer[4] & 0x01)        << 8)        | buffer[5];        // 1 + 8 =  9 bits of rudder
  1607.  
  1608.         WARNING(state.xAxis        <= 0x3ff,    "SidewinderPro::ParseData xAxis has more than 10 bits of data");
  1609.         WARNING(state.yAxis        <= 0x3ff,    "SidewinderPro::ParseData yAxis has more than 10 bits of data");
  1610.         WARNING(state.throttle    <= 0x3ff,    "SidewinderPro::ParseData throttle has more than 10 bits of data");
  1611.         WARNING(state.rudder    <= 0x1ff,    "SidewinderPro::ParseData rudder has more than 9 bits of data");
  1612.     
  1613.         // reverse axis to transform to ISp coordinate system
  1614.         state.yAxis        = 0x3ff - state.yAxis;
  1615.         state.throttle    = 0x3ff - state.throttle;
  1616.  
  1617.         // read and convert the hat
  1618.         state.hat         = (buffer[4] & kHiNibble) >> 4;                            // hat
  1619.         
  1620.         WARNING(state.hat <= 8,                "SidewinderPro::ParseData hat should be 0..8");
  1621.         switch(state.hat)
  1622.         {
  1623.             case 0:        state.hat = kISpPadIdle;         break;
  1624.             case 1:        state.hat = kISpPadUp;            break;
  1625.             case 2:        state.hat = kISpPadUpRight;        break;
  1626.             case 3:        state.hat = kISpPadRight;        break;
  1627.             case 4:        state.hat = kISpPadDownRight;    break;
  1628.             case 5:        state.hat = kISpPadDown;        break;
  1629.             case 6:        state.hat = kISpPadDownLeft;    break;
  1630.             case 7:        state.hat = kISpPadLeft;        break;
  1631.             case 8:        state.hat = kISpPadUpLeft;        break;
  1632.             default:      state.hat = kISpPadIdle;        break;
  1633.         }
  1634.     
  1635.         // read the buttons
  1636.         state.buttons[kTrigger]         = !(buffer[6] & 0x10);                        // trigger
  1637.         state.buttons[kTopButton]         = !(buffer[6] & 0x20);                        // thumb
  1638.         state.buttons[kStickHighButton] = !(buffer[6] & 0x40);                        // stick hi
  1639.         state.buttons[kStickLowButton]     = !(buffer[6] & 0x80);                        // stick lo
  1640.  
  1641.         state.buttons[kBaseFarLeft]     = !(buffer[1] & 0x10);                        // top left
  1642.         state.buttons[kBaseFarRight]     = !(buffer[1] & 0x20);                         // top right
  1643.         state.buttons[kBaseNearLeft]     = !(buffer[1] & 0x80);                        // low left
  1644.         state.buttons[kBaseNearRight]     = !(buffer[1] & 0x40);                         // low right
  1645.  
  1646.         // scale and calibrate
  1647.         state.xAxis     = state.xAxis         << 22;
  1648.         state.yAxis     = state.yAxis         << 22;
  1649.         state.throttle    = state.throttle    << 22;
  1650.         state.rudder     = state.rudder        << 23;
  1651.  
  1652.         // push the data where it changed
  1653.         if (state.xAxis != mOldState.xAxis)
  1654.         {
  1655.             err = ISpElement_PushSimpleData(mXAxis, state.xAxis, &time);
  1656.             WARNING(err == noErr, "push failed in parse");
  1657.         }
  1658.  
  1659.         if (state.yAxis != mOldState.yAxis)
  1660.         {
  1661.             err = ISpElement_PushSimpleData(mYAxis, state.yAxis, &time);
  1662.             WARNING(err == noErr, "push failed in parse");
  1663.         }
  1664.  
  1665.         if (state.throttle != mOldState.throttle)
  1666.         {
  1667.             err = ISpElement_PushSimpleData(mThrottle, state.throttle, &time);
  1668.             WARNING(err == noErr, "push failed in parse");
  1669.         }
  1670.  
  1671.         if (state.rudder != mOldState.rudder)
  1672.         {
  1673.             err = ISpElement_PushSimpleData(mRudder, state.rudder, &time);
  1674.             WARNING(err == noErr, "push failed in parse");
  1675.         }
  1676.     
  1677.         if (state.hat != mOldState.hat)
  1678.         {
  1679.             err = ISpElement_PushSimpleData(mHat, state.hat, &time);
  1680.             WARNING(err == noErr, "push failed in parse");
  1681.         }
  1682.         
  1683.         UInt32 button_itr;
  1684.         for(button_itr = 0; button_itr < kNumSidewinderButtons; button_itr++)
  1685.         {
  1686.             if (state.buttons[button_itr] != mOldState.buttons[button_itr])
  1687.             {
  1688.                 err = ISpElement_PushSimpleData(mButtons[button_itr], state.buttons[button_itr], &time);
  1689.                 WARNING(err == noErr, "push failed for generic button");
  1690.             }
  1691.         }
  1692.         
  1693.         HighLevelData currentHLData;
  1694.         StateToHighLevelData (state, currentHLData);
  1695.         
  1696.         // if we are in high level mode do the high level actions        
  1697.         if (mVirtualElementsValid)
  1698.         { 
  1699.             SetAsFields(currentHLData);
  1700.             PushDataToVirtuals(currentHLData);
  1701.         }
  1702.  
  1703.         mOldState = state;
  1704.         mOldHLData = currentHLData;
  1705.     }
  1706. }
  1707.  
  1708. #if !__MWERKS__
  1709.     inline 
  1710. #endif
  1711. void    SidewinderPro::StateToHighLevelData(const SidewinderStateStruct &inState, HighLevelData& outHLData)
  1712. {
  1713.     outHLData.xAxis = inState.xAxis;
  1714.     outHLData.yAxis = inState.yAxis;
  1715.     outHLData.throttle = inState.throttle;
  1716.     outHLData.rudder = inState.rudder;
  1717.     outHLData.hat = inState.hat;
  1718.     
  1719.     for (UInt32 button_itr = 0; button_itr < kNumSidewinderButtons; button_itr++)
  1720.         outHLData.buttons[button_itr] = inState.buttons[button_itr];
  1721.  
  1722.     // axis reversal
  1723.     if (mReverseStickVertical)
  1724.         outHLData.yAxis    = kISpAxisMaximum - outHLData.yAxis;
  1725.     if (mReverseThrottle)
  1726.         outHLData.throttle = kISpAxisMaximum - outHLData.throttle;
  1727.     if (mReverseRudder)
  1728.         outHLData.rudder = kISpAxisMaximum - outHLData.rudder;
  1729.     if (mReverseHatVertical)
  1730.         outHLData.hat = DPadReverseVertical (outHLData.hat);
  1731. }
  1732.  
  1733.  
  1734. /*
  1735.  *
  1736.  * IsPressed
  1737.  *
  1738.  * This function returns true if this dialog item 'pressed' (ie on the device)
  1739.  *
  1740.  */
  1741.  
  1742. Boolean SidewinderPro::IsPressed (short inDialogItem)
  1743. {
  1744.     UInt32 array_index = inDialogItem - mBaseDITLCount - kDialogItem_FirstPopup;
  1745.     
  1746.     WARNING(array_index >= 0,                        "IsPressed array_index out of range (to small)");
  1747.     WARNING(array_index < kDialogItem_NumPopups,    "IsPressed array_index out of range (to large)");
  1748.  
  1749.     return mPopupPressed[array_index];
  1750. }
  1751.  
  1752. void SidewinderPro::UpdateAllButtons(void)
  1753. {
  1754.     HighLevelData theHLData = mOldHLData;
  1755.  
  1756.     UpdateSingleButton (theHLData.xAxis_as_buttons[0],        kDialogItem_StickLeft);
  1757.     UpdateSingleButton (theHLData.xAxis_as_buttons[1],        kDialogItem_StickRight);    
  1758.     UpdateSingleButton (theHLData.yAxis_as_buttons[0],        kDialogItem_StickDown);
  1759.     UpdateSingleButton (theHLData.yAxis_as_buttons[1],        kDialogItem_StickUp);
  1760.     
  1761.     UpdateSingleButton (theHLData.throttle_as_buttons[0],    kDialogItem_ThrottleLower);
  1762.     UpdateSingleButton (theHLData.throttle_as_buttons[1],    kDialogItem_ThrottleHigher);
  1763.     
  1764.     UpdateSingleButton (theHLData.rudder_as_buttons[0],        kDialogItem_RudderLeft);
  1765.     UpdateSingleButton (theHLData.rudder_as_buttons[1],        kDialogItem_RudderRight);
  1766.  
  1767.     for(UInt32 button_itr = 0; button_itr < kNumSidewinderButtons; button_itr++)
  1768.         UpdateSingleButton(theHLData.buttons[button_itr],    kDialogItem_Trigger + button_itr);
  1769.  
  1770.     UpdateSingleButton (theHLData.hat_as_buttons[0],        kDialogItem_DPadUp);
  1771.     UpdateSingleButton (theHLData.hat_as_buttons[2],        kDialogItem_DPadDown);
  1772.     UpdateSingleButton (theHLData.hat_as_buttons[1],        kDialogItem_DPadLeft);
  1773.     UpdateSingleButton (theHLData.hat_as_buttons[3],        kDialogItem_DPadRight);
  1774. }
  1775.  
  1776. void SidewinderPro::UpdateSingleButton(UInt32 curButton, UInt32 index)
  1777. {
  1778.     WARNING(mDialog != nil,        "SidewinderPro::UpdateSingleButton mDialog was nil");
  1779.     WARNING(mVisable,            "SidewinderPro::UpdateSingleButton mVisable was false");
  1780.  
  1781.     WARNING(index > 0,                        "SidewinderPro::UpdateSingleButton index out of range (to small)");
  1782.     WARNING(index <= kDialogItem_NumPopups,    "SidewinderPro::UpdateSingleButton index out of range (to large)");
  1783.  
  1784.     UInt32 array_index = index - kDialogItem_FirstPopup;
  1785.     Boolean changed = false;    
  1786.     
  1787.     if ((!mPopupPressed[array_index]) && (curButton))
  1788.     {
  1789.         mPopupPressed[array_index] = true;
  1790.         changed = true;
  1791.     }
  1792.     else if ((mPopupPressed[array_index]) && (!curButton))
  1793.     {
  1794.         mPopupPressed[array_index] = false;
  1795.         changed = true;
  1796.     }
  1797.  
  1798.     if (changed)
  1799.         { PlotPopupIcon(mBaseDITLCount + index, ttNone); }
  1800. }
  1801.  
  1802.